package com.cms.jy.copy;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cms.jy.utils.LyricFenjingUtil;
import com.cms.jy.utils.OkHttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * Jy工具类
 */
@Slf4j
public class JyUtils {

    private String API_KEY = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJvY2FQTjYxZGVyLW9FT3J0RFpmR20tQkUtTXhFIiwiaWF0IjowfQ.I4v2LBiMELMl3dBpaZVqEazVMDMIa2QWLtObQ0YIpO534xxYT-SgpzGYTfVtRIRCCvWAgj3aEeXbPzSbGal1kGypyctKtjiukPgcBfy_XupXkhQvUT5Iaqx_lSGdKRdSo9haNuHeXimt1VcRy3HzMb7mL3Mmg3B3-DCdJN47tx_mSMOX67h04BHVUVTpHDvWdYX1Pzzrxk_uakvcz-K7HY4fEhtmO9CjWIU-66lBMv2T4szvJjOJZM6FipXRDe4RMPMDOV9z2tB3lHmybFGhDhGQxb8fF-PPfRbK-9w_UxGkjGQC4L_GfBxpW0EXbv8ReYlpHnh-W1p5Lq4IHTdnKg";

    private OkHttpUtils okHttpUtils;
    //https://open.capcutapi.top/cut_jianying
    private String API_URL = "http://127.0.0.1:9001";

    private final String RES_BASE_URL = "http://localhost:8080/video";

    public String RES_TPL_URL = RES_BASE_URL + "/tpl/music";

    private String RES_VIDEO_URL = RES_BASE_URL + "/视频/横屏";

    private String RES_SC_URL = RES_BASE_URL + "/sc";

    private String VIDEO_PATH = "E:\\自媒体\\素材\\视频\\横屏";

    private String JY_CRAFT_PATH = "E:\\自媒体\\JianyingPro Drafts";

    public void setAPI_KEY(String API_KEY) {
        this.API_KEY = API_KEY;
    }

    public void setAPI_URL(String API_URL) {
        this.API_URL = API_URL;
    }

    public void setRES_VIDEO_URL(String RES_VIDEO_URL) {
        this.RES_VIDEO_URL = this.RES_BASE_URL + RES_VIDEO_URL;
    }

    public void setRES_TPL_URL(String RES_TPL_URL) {
        this.RES_TPL_URL = this.RES_BASE_URL + RES_TPL_URL;
    }

    public void setRES_SC_URL(String RES_SC_URL) {
        this.RES_SC_URL = this.RES_BASE_URL + RES_SC_URL;
    }

    public void setVIDEO_PATH(String VIDEO_PATH) {
        this.VIDEO_PATH = VIDEO_PATH;
    }

    public void setJY_CRAFT_PATH(String JY_CRAFT_PATH) {
        this.JY_CRAFT_PATH = JY_CRAFT_PATH;
    }

    public JyUtils() {
        this.okHttpUtils = new OkHttpUtils();
    }

    /**
     * 创建草稿
     *
     * @param width  视频宽度（选填，默认1920）
     * @param height 视频高度（选填，默认1080）
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String createDraft(Integer width, Integer height) throws Exception {
        String url = API_URL + "/create_draft";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        StringBuilder bodyBuilder = new StringBuilder();
        Map<String, Object> body = new HashMap<>();
        body.put("width", null == width ? 1920 : width);
        body.put("height", null == height ? 1080 : height);
        // 发送POST请求，使用不安全的SSL连接
        return okHttpUtils.postJson(url, JSON.toJSON(body).toString(), headers, true);
    }

    /**
     * 创建草稿（使用默认宽高）
     *
     * @return 响应内容
     * @throws Exception IO异常
     */
    public String createDraft() throws Exception {
        return createDraft(null, null);
    }

    /**
     * 创建草稿并返回draft_id
     *
     * @param width  视频宽度（可选）
     * @param height 视频高度（可选）
     * @return draft_id
     * @throws Exception IO异常
     */
    public String createDraftAndGetId(Integer width, Integer height) throws Exception {
        String response = createDraft(width, height);
        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("创建草稿失败：" + error);
        }
        log.info("创建草稿成功，预览地址：{}", jsonObject.getJSONObject("output").getString("draft_url"));
        return jsonObject.getJSONObject("output").getString("draft_id");
    }

    /**
     * 创建草稿并返回draft_id（使用默认宽高）
     *
     * @return draft_id
     * @throws Exception IO异常
     */
    public String createDraftAndGetId() throws Exception {
        log.info("正在创建草稿...");
        return createDraftAndGetId(null, null);
    }

    /**
     * 加载草稿
     *
     * @param draftName
     * @return 响应内容
     * @throws IOException IO异常
     */
    public String loadDraft(String  draftName) throws Exception {
        String url = API_URL + "/load_existing_draft";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        StringBuilder bodyBuilder = new StringBuilder();
        Map<String, Object> body = new HashMap<>();
        body.put("draft_name", draftName);
        // 发送POST请求，使用不安全的SSL连接
        return okHttpUtils.postJson(url, JSON.toJSON(body).toString(), headers, true);
    }

    /**
     * 添加图片到草稿
     *
     * @param imageUrl               图片URL
     * @param start                  正在时间
     * @param end                    结束时间
     * @param width                  视频宽度
     * @param height                 视频高度
     * @param draftId                草稿ID
     * @param transformX             X轴变换
     * @param transformY             Y轴变换
     * @param scaleX                 X轴缩放
     * @param scaleY                 Y轴缩放
     * @param trackName              轨道名称
     * @param relativeIndex          相对索引
     * @param introAnimation         入场动画
     * @param introAnimationDuration 入场动画时长
     * @param outroAnimation         出场动画
     * @param outroAnimationDuration 出场动画时长
     * @param transition             转场效果
     * @param transitionDuration     转场时长
     * @param maskType               遮罩类型
     * @param maskCenterX            遮罩中心X坐标
     * @param maskCenterY            遮罩中心Y坐标
     * @param maskSize               遮罩大小
     * @param maskRotation           遮罩旋转角度
     * @param maskFeather            遮罩羽化
     * @param maskInvert             遮罩反转
     * @param maskRectWidth          遮罩矩形宽度
     * @param maskRoundCorner        遮罩圆角
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String addImage(String imageUrl, double start, double end, int width, int height,
                           String draftId, double transformX, double transformY,
                           double scaleX, double scaleY, String trackName, int relativeIndex,
                           String introAnimation, double introAnimationDuration,
                           String outroAnimation, double outroAnimationDuration,
                           String transition, double transitionDuration,
                           String maskType, double maskCenterX, double maskCenterY,
                           double maskSize, double maskRotation, int maskFeather,
                           boolean maskInvert, int maskRectWidth, int maskRoundCorner) throws Exception {

        String url = API_URL + "/add_image";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("image_url", imageUrl);
        body.put("start", start);
        body.put("end", end);
        body.put("width", width);
        body.put("height", height);
        body.put("draft_id", draftId);
        body.put("transform_x", transformX);
        body.put("transform_y", transformY);
        body.put("scale_x", scaleX);
        body.put("scale_y", scaleY);
        body.put("track_name", trackName);
        body.put("relative_index", relativeIndex);
        body.put("intro_animation", introAnimation);
        body.put("intro_animation_duration", introAnimationDuration);
        body.put("outro_animation", outroAnimation);
        body.put("outro_animation_duration", outroAnimationDuration);
        body.put("transition", transition);
        body.put("transition_duration", transitionDuration);
        body.put("mask_type", maskType);
        body.put("mask_center_x", maskCenterX);
        body.put("mask_center_y", maskCenterY);
        body.put("mask_size", maskSize);
        body.put("mask_rotation", maskRotation);
        body.put("mask_feather", maskFeather);
        body.put("mask_invert", maskInvert);
        body.put("mask_rect_width", maskRectWidth);
        body.put("mask_round_corner", maskRoundCorner);

        // 发送POST请求，使用不安全的SSL连接
        return okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
    }

    /**
     * 添加图片到草稿（简化版本）
     *
     * @param imageUrl 图片URL
     * @param draftId  草稿ID
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String addImage(String imageUrl, String draftId) throws Exception {
        String response = addImage(imageUrl, 0, 5.0, 1920, 1080, draftId, 0.2, 0.2, 1, 1,
                "video_main", 99, "放大", 0.5, "闪现", 0.5, "上移", 0.5,
                "矩形", 0.5, 0.5, 0.7, 45.0, 2, true, 8, 10);
        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("添加图片失败：" + error);
        }
        return jsonObject.getJSONObject("output").getString("draft_id");
    }

    /**
     * 保存草稿
     *
     * @param draftId     草稿ID
     * @param draftFolder 草稿文件夹路径
     * @param isCapcut    是否为CapCut格式 (0: 否, 1: 是)
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String saveDraft(String draftId, String draftName, String templatePath, String draftFolder, int isCapcut) throws Exception {
        String url = API_URL + "/save_draft";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("draft_id", draftId);
        body.put("draft_folder", draftFolder);
        body.put("is_capcut", isCapcut);

        if (StringUtils.isNotBlank(draftName)) {
            body.put("draft_name", draftName);
        }
        if (StringUtils.isNotBlank(templatePath)) {
            body.put("template_path", templatePath);
        }

        // 发送POST请求，使用不安全的SSL连接
        return okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
    }

    /**
     * 保存草稿（使用默认参数）
     *
     * @param draftId 草稿ID
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String saveDraft(String draftId, String draftName, String templatePath) throws Exception {
        log.info("正在保存草稿...");
        String response = saveDraft(draftId, draftName, templatePath, JY_CRAFT_PATH, 0);
        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("保存草稿失败：" + error);
        }
        return jsonObject.getJSONObject("output").getString("draft_url");
    }

    /**
     * 保存存在的草稿（使用默认参数）
     *
     * @param draftId 草稿ID
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String saveExistDraft(String draftId, String draftName, String drafPath, boolean isCapcut) throws Exception {
        log.info("正在保存存在的草稿...");
        String url = API_URL + "/save_draft";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("draft_id", draftId);
        body.put("draft_folder", null == drafPath ? JY_CRAFT_PATH : drafPath);
        body.put("is_capcut", isCapcut);

        if (StringUtils.isNotBlank(draftName)) {
            body.put("draft_name", draftName);
        }

        // 发送POST请求，使用不安全的SSL连接
        return okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
    }

    /**
     * 添加音频到草稿
     *
     * @param audioUrl     音频文件URL（必填）
     * @param start        音频素材的起始截取时间（秒，默认0）
     * @param end          音频素材的结束截取时间（秒，可选，默认取完整音频长度）
     * @param draftId      草稿ID（可选，用于指定操作的草稿）
     * @param volume       音量大小（默认1.0）
     * @param targetStart  音频在时间线上的起始位置（秒，默认0）
     * @param speed        音频速度（默认1.0，>1加速，<1减速）
     * @param trackName    轨道名称（默认"audio_main"）
     * @param duration     音频素材的总时长（秒）主动设置可以提升请求速度
     * @param effectType   音效类型
     * @param effectParams 音效参数（可选，根据effect_type设置）
     * @param width        视频宽度（默认1920）
     * @param height       视频高度（默认1080）
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String addAudio(String audioUrl, double start, Double end, String draftId, Double volume,
                           double targetStart, Double speed, String trackName, Double duration,
                           String effectType, List<Object> effectParams, Integer width, Integer height) throws Exception {
        String url = API_URL + "/add_audio";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("audio_url", audioUrl);
        body.put("start", start);

        if (end != null) {
            body.put("end", end);
        }

        if (draftId != null) {
            body.put("draft_id", draftId);
        }

        if (volume != null) {
            body.put("volume", volume);
        }

        body.put("target_start", targetStart);

        if (speed != null) {
            body.put("speed", speed);
        }

        if (trackName != null) {
            body.put("track_name", trackName);
        }

        if (duration != null) {
            body.put("duration", duration);
        }

        if (effectType != null) {
            body.put("effect_type", effectType);
        }

        if (effectParams != null) {
            body.put("effect_params", effectParams);
        }

        if (width != null) {
            body.put("width", width);
        }

        if (height != null) {
            body.put("height", height);
        }

        // 发送POST请求，使用不安全的SSL连接
        return okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
    }

    /**
     * 添加音频到草稿（简化版本）
     *
     * @param audioUrl 音频文件URL
     * @param draftId  草稿ID
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String addAudio2(String audioUrl, String draftId, Double start, Double end, Double taretStart) throws Exception {
        log.info("正在添加音频到草稿...");
        String response = addAudio(audioUrl, start, end, draftId, null, taretStart, null, null, null, null, null, 1920, 1080);
        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("添加音频失败：" + error);
        }
        return jsonObject.getJSONObject("output").getString("draft_id");
    }

    /**
     * 添加文本到草稿（完整版本）
     *
     * @param text             文本内容（必填，核心显示内容）
     * @param start            文本在时间线的起始时间（秒，必填）
     * @param end              文本在时间线的结束时间（秒，必填）
     * @param draftId          草稿ID（选填，用于关联操作的草稿）
     * @param transformY       Y轴变换参数（选填，默认0）
     * @param transformX       X轴变换参数（选填，默认0）
     * @param font             字体（选填，默认"系统"）
     * @param fontColor        字体颜色（选填，默认红色#FF0000）
     * @param fontSize         字体大小（选填，默认8.0）
     * @param trackName        轨道名称（选填，默认"text_main"）
     * @param vertical         是否垂直显示（选填，默认false）
     * @param fontAlpha        字体透明度（选填，默认1.0，范围0.0-1.0）
     * @param fixedWidth       固定宽度（选填，默认-1，-1表示不固定）
     * @param fixedHeight      固定高度（选填，默认-1，-1表示不固定）
     * @param borderAlpha      描边透明度（选填，默认1.0）
     * @param borderColor      描边颜色（选填，默认黑色#000000）
     * @param borderWidth      描边宽度（选填，默认0.0）
     * @param backgroundColor  背景颜色（选填，默认黑色#000000）
     * @param backgroundStyle  背景样式（选填，默认0，需与业务支持的样式枚举匹配）
     * @param backgroundAlpha  背景透明度（选填，默认0.0）
     * @param introAnimation   入场动画类型（选填，如"向下飞入"等）
     * @param introDuration    入场动画持续时间（秒，选填，默认0.5）
     * @param outroAnimation   出场动画类型（选填，如"向下滑动"淡出等）
     * @param outroDuration    出场动画持续时间（秒，选填，默认0.5）
     * @param width            画布宽度（选填，默认1080）
     * @param height           画布高度（选填，默认1920）
     * @param textStyles       文本样式列表（选填）
     * @param bubbleEffectId   气泡效果ID（选填）
     * @param bubbleResourceId 气泡资源ID（选填）
     * @param effectEffectId   花字效果ID（选填）
     * @param letterSpacing    字符间距（选填）
     * @param lineSpacing      行间距（选填）
     * @param shadowEnabled    是否启用阴影（选填，默认false，true为启用阴影效果）
     * @param shadowAlpha      阴影透明度（选填，默认0.9，范围0.0-1.0）
     * @param shadowAngle      阴影角度（选填，默认-45.0，范围-180.0-180.0，单位为度）
     * @param shadowColor      阴影颜色（选填，默认#000000，支持十六进制颜色码）
     * @param shadowDistance   阴影距离（选填，默认5.0，范围0-100，控制阴影与文本的间距）
     * @param shadowSmoothing  阴影平滑度（选填，默认0.15，范围0.0-1.0，值越大阴影越模糊）
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String addText(String text, double start, double end, String draftId, Double transformY,
                          Double transformX, String font, String fontColor, Double fontSize,
                          String trackName, Boolean vertical, Double fontAlpha, Double fixedWidth,
                          Double fixedHeight, Double borderAlpha, String borderColor,
                          Double borderWidth, String backgroundColor, Integer backgroundStyle,
                          Double backgroundAlpha, String introAnimation, Double introDuration,
                          String outroAnimation, Double outroDuration, Integer width, Integer height,
                          List<Map<String, Object>> textStyles, String bubbleEffectId,
                          String bubbleResourceId, String effectEffectId, Integer letterSpacing,
                          Integer lineSpacing, Boolean shadowEnabled, Double shadowAlpha,
                          Double shadowAngle, String shadowColor, Integer shadowDistance,
                          Double shadowSmoothing, Double scaleX, Double scaleY) throws Exception {
        String url = API_URL + "/add_text";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("text", text);
        body.put("start", start);
        body.put("end", end);

        if (draftId != null) {
            body.put("draft_id", draftId);
        }

        if (transformY != null) {
            body.put("transform_y", transformY);
        }

        if (transformX != null) {
            body.put("transform_x", transformX);
        }

        if (font != null) {
            body.put("font", font);
        }

        if (fontColor != null) {
            body.put("font_color", fontColor);
        } else {
            body.put("font_color", "#FFFFFF");
        }

        if (fontSize != null) {
            body.put("font_size", fontSize);
        } else {
            body.put("font_size", 15.0);
        }

        if (trackName != null) {
            body.put("track_name", trackName);
        }

        if (vertical != null) {
            body.put("vertical", vertical);
        }

        if (fontAlpha != null) {
            body.put("font_alpha", fontAlpha);
        }

        if (fixedWidth != null) {
            body.put("fixed_width", fixedWidth);
        } else {
            body.put("fixed_width", -1);
        }

        if (fixedHeight != null) {
            body.put("fixed_height", fixedHeight);
        } else {
            body.put("fixed_height", -1);
        }

        if (borderAlpha != null) {
            body.put("border_alpha", borderAlpha);
        }

        if (borderColor != null) {
            body.put("border_color", borderColor);
        }

        if (borderWidth != null) {
            body.put("border_width", borderWidth);
        }

        if (backgroundColor != null) {
            body.put("background_color", backgroundColor);
        }

        if (backgroundStyle != null) {
            body.put("background_style", backgroundStyle);
        }

        if (backgroundAlpha != null) {
            body.put("background_alpha", backgroundAlpha);
        }

        if (introAnimation != null) {
            body.put("intro_animation", introAnimation);
        }

        if (introDuration != null) {
            body.put("intro_duration", introDuration);
        }

        if (outroAnimation != null) {
            body.put("outro_animation", outroAnimation);
        }

        if (outroDuration != null) {
            body.put("outro_duration", outroDuration);
        }

        if (width != null) {
            body.put("width", width);
        }

        if (height != null) {
            body.put("height", height);
        }

        if (textStyles != null) {
            body.put("text_styles", textStyles);
        }

        // 气泡和花字效果参数
        if (bubbleEffectId != null) {
            body.put("bubble_effect_id", bubbleEffectId);
        }

        if (bubbleResourceId != null) {
            body.put("bubble_resource_id", bubbleResourceId);
        }

        if (effectEffectId != null) {
            body.put("effect_effect_id", effectEffectId);
        }

        if (letterSpacing != null) {
            body.put("letter_spacing", letterSpacing);
        }

        if (lineSpacing != null) {
            body.put("line_spacing", lineSpacing);
        }

        // 阴影效果参数
        if (shadowEnabled != null) {
            body.put("shadow_enabled", shadowEnabled);
        }

        if (shadowAlpha != null) {
            body.put("shadow_alpha", shadowAlpha);
        }

        if (shadowAngle != null) {
            body.put("shadow_angle", shadowAngle);
        }

        if (shadowColor != null) {
            body.put("shadow_color", shadowColor);
        }

        if (shadowDistance != null) {
            body.put("shadow_distance", shadowDistance);
        }

        if (shadowSmoothing != null) {
            body.put("shadow_smoothing", shadowSmoothing);
        }

        if (scaleX != null) {
            body.put("scale_x", scaleX);
        }

        if (scaleY != null) {
            body.put("scale_y", scaleY);
        }

        // 发送POST请求，使用不安全的SSL连接
        String response = okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("添加文字失败：" + error);
        }
        return jsonObject.getJSONObject("output").getString("draft_id");
    }

    /**
     * 添加文本到草稿（简化版本）
     *
     * @param text    文本内容
     * @param start   起始时间（秒）
     * @param end     结束时间（秒）
     * @param draftId 草稿ID
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String addText(String text, double start, double end, String draftId, Double fontSize,
                          String introAnimation, Double introDuration,
                          String outroAnimation, Double outroDuration,
                          Double transformX, Double transformY, Double scaleX, Double scaleY) throws Exception {
        String response = addText(text, start, end, draftId, transformY, transformX, null, null, fontSize, null, null, null,
                null, null, null, null, null, null, null, null,
                introAnimation, introDuration, outroAnimation, outroDuration, 1920,
                1080, null, null, null, null, null, null, null, null,
                null, null, null, null, scaleX, scaleY);

        return response;
    }


    /**
     * 解析SRT字幕文件内容并添加到草稿
     *
     * @param srtContent SRT字幕内容
     * @param draftId    草稿ID
     * @return 最后一个添加的文本的草稿ID
     * @throws Exception IO异常
     */
    public String addTextFromSrt(String srtContent, String draftId) throws Exception {
        String[] lines = srtContent.split("\n");
        String lastDraftId = draftId;
        List<Map<String, Object>> srt = new ArrayList<>();
        for (int i = 0; i < lines.length; i++) {
            String line = lines[i].trim();

            // 检查是否为字幕序号行
            if (line.matches("\\d+") && i + 1 < lines.length) {
                // 下一行应该是时间码
                String timeLine = lines[i + 1].trim();
                if (timeLine.contains("-->")) {
                    String[] times = timeLine.split("-->");
                    if (times.length == 2 && i + 2 < lines.length) {
                        // 解析正在时间
                        double startTime = parseSrtTime(times[0].trim());
                        // 解析结束时间
                        double endTime = parseSrtTime(times[1].trim());

                        // 获取字幕文本（可能跨越多行）
                        StringBuilder textBuilder = new StringBuilder();
                        int j = i + 2;
                        while (j < lines.length && !lines[j].trim().isEmpty() && !lines[j].trim().matches("\\d+")) {
                            if (textBuilder.length() > 0) {
                                textBuilder.append("\n");
                            }
                            textBuilder.append(lines[j].trim());
                            j++;
                        }

                        String text = textBuilder.toString();
                        log.info("添加文本：{}, 开始：{}，结束：{}", text, startTime, endTime);
                        // 添加文本到草稿
                        double dis = endTime - startTime;
                        text = text.trim().replaceAll("[^\\x20-\\x7e\\x{4e00}-\\x{9fff}]", "");
                        lastDraftId = addText(text, startTime, endTime, draftId, 5.0, "轻微放大", dis / 2, "渐隐", dis / 4,
                                0.0, -0.73, null, null);
                        String videoUrl = RES_TPL_URL + "/0M-FWMM--CQIS-XL63-ZQMZ-IHIZ8CFSZ65N.mov";
                        log.info("添加视频素材...,开始：{}，结束：{}", startTime, endTime);
                        // 字幕背景云烟视频
                        lastDraftId = addVideo(videoUrl, 0.0, 0.0,
                                1920, 1080, draftId, calculateCoverY(-625), calculateCoverX(458),
                                0.84, 0.84, 4.5 / dis, startTime, "test_00", null, dis, null,
                                null, -1.0, null,
                                null, null, null, null, null, false, null,
                                null, null, 1.0, "screen", null, null);

                        Map<String, Object> srtItem = new HashMap<>();
                        srtItem.put("text", text);
                        srtItem.put("start", startTime);
                        srtItem.put("end", endTime);
                        srt.add(srtItem);
//                        if (i>3) {
//                            break;
//                        }
                        i = j - 1; // 更新索引位置
                    }
                }
            }
        }

        // 生成分镜数据
        JSONArray fenjin = LyricFenjingUtil.generateFenjing(srtContent);
        // 处理分镜数据
        List<JSONObject> fenjins = LyricFenjingUtil.processFenjins(fenjin);
        double preStart = 0.0, preEnd = 0.0;
        List<String> usedVideoUrls = new ArrayList<>();
        for (JSONObject fj : fenjins) {
            // 解析正在时间
            double startTime = parseSrtTime(fj.getString("start"));
            // 解析结束时间
            double endTime = parseSrtTime(fj.getString("end"));
            double duration = endTime - preStart;
            preEnd = endTime;
            String videoUrl = getVideoUrl(fj.getString("keywords"), usedVideoUrls);
            if (usedVideoUrls.contains(videoUrl)) {
                for (int attempt = 0; attempt < 3; attempt++) {
                    videoUrl = getVideoUrl(fj.getString("keywords"), usedVideoUrls);
                    // 如果URL未使用过，则返回该URL
                    if (!usedVideoUrls.contains(videoUrl)) {
                        usedVideoUrls.add(videoUrl); // 标记为已使用
                        return videoUrl;
                    }
                    log.warn("第{}次尝试获取视频URL，但URL已使用: {}", attempt + 1, videoUrl);
                }
            } else {
                usedVideoUrls.add(videoUrl);
            }


            log.info("添加分镜视频素材...,开始：{}，结束：{}, {}", startTime, endTime, videoUrl);
            try {
                addVideo(videoUrl, 0.0, duration,
                        1920, 1080, draftId, null, null,
                        null, null, null, preStart, "video_main", null, duration, "模糊",
                        1.3, -1.0, null,
                        null, null, null, null, null, false, null,
                        null, null, 1.0, null, null, null);
                preStart = endTime;
            } catch (Exception e) {
                throw new Exception(e);
            }
        }
        ;

        // 开头 结尾视频
        String startVideoURL = RES_TPL_URL + "/BH-QBRS--3ZGI-JHOO-IO7H-XWOHF1L3QXV8.mp4";
        addVideo(startVideoURL, 0.0, 5.1,
                1920, 1080, draftId, null, null,
                null, null, null, 0.0, "test_99", null, 5.1, null,
                null, -1.0, null,
                null, null, null, null, null, false, null,
                null, null, 1.0, null, null, null);
        String endVideoURL = RES_TPL_URL + "/FR-9QEP--B6P4-LH2B-Z787-9WQ8E9LM5TD8.mp4";
        addVideo(endVideoURL, 0.0, 4.0,
                1920, 1080, draftId, null, null,
                null, null, null, preEnd - 4.0, "test_99", null, 4.0, null,
                null, -1.0, null,
                null, null, null, null, null, false, null,
                null, null, 1.0, null, null, null);
        // 添加视频材料
        // 第二步：根据语义分组字幕（每组最多4句）
        // List<List<Map<String, Object>>> scenes = groupSubtitlesIntoScenes(srt);

        // 第三步：为每个场景添加文本和视频素材
//        for (int sceneIndex = 0; sceneIndex < scenes.size(); sceneIndex++) {
//            List<Map<String, Object>> scene = scenes.get(sceneIndex);
//
//            // 合并场景中的所有文本
//            StringBuilder combinedText = new StringBuilder();
//            double sceneStart = Double.MAX_VALUE;
//            double sceneEnd = Double.MIN_VALUE;
//
//            for (Map<String, Object> subtitle : scene) {
//                String text = (String) subtitle.get("text");
//                double start = (Double) subtitle.get("start");
//                double end = (Double) subtitle.get("end");
//
//                if (combinedText.length() > 0) {
//                    combinedText.append("\n");
//                }
//                combinedText.append(text);
//
//                if (start < sceneStart) {
//                    sceneStart = start;
//                }
//                if (end > sceneEnd) {
//                    sceneEnd = end;
//                }
//            }
//
//            // 添加文本到草稿
//            double duration = sceneEnd - sceneStart;
//            // 添加视频素材
//            String videoUrl = RES_VIDEO_URL + "/0M-FWMM--CQIS-XL63-ZQMZ-IHIZ8CFSZ65N.mov";
//            log.info("添加视频素材...,开始：{}，结束：{}", sceneStart, sceneEnd);
//            lastDraftId = addVideo(videoUrl, 0.0, 0.0,
//                    1920, 1080, draftId, calculateCoverY(-625), calculateCoverX(458),
//                    0.84, 0.84, 4.5/duration, sceneStart, "test_77_" + sceneIndex, null, duration, null,
//                    null, -1.0, null,
//                    null, null, null, null, null, false, null,
//                    null, null, 1.0, null);
//        }
        return lastDraftId;
    }


    private String getVideoUrl(String keywords, List<String> usedVideoUrls) {
        String dirVideo = VIDEO_PATH;
        File[] files = new File(dirVideo).listFiles();

        // 如果目录为空或无法访问，返回默认视频
        if (files == null || files.length == 0) {
            return RES_VIDEO_URL + "/海水-夕阳.webm";
        }

        // 如果keywords为空，从所有文件中随机选择一个
        if (keywords == null || keywords.trim().isEmpty()) {
            Random random = new Random();
            File randomFile = files[random.nextInt(files.length)];
            return RES_VIDEO_URL + "/" + randomFile.getName();
        }

        // 收集所有匹配关键词的视频文件
        List<File> matchedFiles = new ArrayList<>();
        String[] keywordArray = keywords.split("[,，]"); // 支持中英文逗号分隔
        File bestMatchFile = null;
        int maxMatches = 0;
        // 遍历所有文件，计算每个文件匹配的关键字数量
        for (File file : files) {
            int matchCount = 0;

            if (String.join(",", usedVideoUrls).contains("/" + file.getName())) {
                continue;
            }

            // 计算当前文件匹配的关键字数量
            for (String keyword : keywordArray) {
                keyword = keyword.trim();
                if (!keyword.isEmpty() && file.getName().contains(keyword)) {
                    matchCount++;
                }
            }

            // 如果当前文件匹配度更高，则更新最佳匹配
            if (matchCount > maxMatches) {
                maxMatches = matchCount;
                bestMatchFile = file;
            }
        }

        // 如果有匹配的文件，返回最佳匹配文件
        if (bestMatchFile != null) {
            return RES_VIDEO_URL + "/" + bestMatchFile.getName();
        }

        // 如果没有匹配的文件，从所有文件中随机选择一个
        Random random = new Random();
        File randomFile = files[random.nextInt(files.length)];
        return RES_VIDEO_URL + "/" + randomFile.getName();
    }


    /**
     * 将字幕按语义分组为场景，每组最多4句
     *
     * @param subtitles 字幕列表
     * @return 分组后的场景列表
     */
    private List<List<Map<String, Object>>> groupSubtitlesIntoScenes(List<Map<String, Object>> subtitles) {
        List<List<Map<String, Object>>> scenes = new ArrayList<>();
        List<Map<String, Object>> currentScene = new ArrayList<>();

        for (int i = 0; i < subtitles.size(); i++) {
            Map<String, Object> subtitle = subtitles.get(i);
            currentScene.add(subtitle);

            // 如果当前场景达到4句，或者检测到语义分割点，则结束当前场景
            if (currentScene.size() >= 4 || shouldSplitScene(subtitles, i)) {
                scenes.add(new ArrayList<>(currentScene));
                currentScene.clear();
            }
        }

        // 添加最后一个场景（如果不为空）
        if (!currentScene.isEmpty()) {
            scenes.add(currentScene);
        }

        return scenes;
    }

    /**
     * 判断是否应该在指定位置分割场景
     * 这里可以添加更复杂的语义分析逻辑
     *
     * @param subtitles    字幕列表
     * @param currentIndex 当前索引
     * @return 是否应该分割场景
     */
    private boolean shouldSplitScene(List<Map<String, Object>> subtitles, int currentIndex) {
        // 随机分割逻辑
        Random random = new Random();

        // 有一定概率进行分割（例如30%的概率）
        double splitProbability = 0.3;

        // 如果当前场景已达到最大句数(4句)，则必须分割
        // 这个检查应该在调用此方法的地方进行，这里只处理随机分割逻辑

        if (currentIndex < subtitles.size() - 1) {
            // 生成0.0到1.0之间的随机数，如果小于分割概率则进行分割
            if (random.nextDouble() < splitProbability) {
                return true;
            }

            // 另外，如果当前句子以句号、感叹号或问号结尾，则增加分割概率
            Map<String, Object> current = subtitles.get(currentIndex);
            String currentText = (String) current.get("text");

            if (currentText.endsWith("。") || currentText.endsWith("！") || currentText.endsWith("？")) {
                // 对于以结束标点结尾的句子，增加分割概率到50%
                if (random.nextDouble() < 0.5) {
                    return true;
                }
            }
        }

        return false;
    }


    /**
     * 解析SRT时间格式为秒数
     *
     * @param timeStr SRT时间字符串，格式为 HH:mm:ss,mmm
     * @return 时间（秒）
     */
    private double parseSrtTime(String timeStr) {
        String[] parts = timeStr.split("[:,]");
        if (parts.length == 4) {
            int hours = Integer.parseInt(parts[0]);
            int minutes = Integer.parseInt(parts[1]);
            int seconds = Integer.parseInt(parts[2]);
            int milliseconds = Integer.parseInt(parts[3]);
            return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000.0;
        }
        return 0.0;
    }

    /**
     * 简化版本：添加SRT字幕到草稿
     *
     * @param filePath SRT字幕文件
     * @param draftId  草稿ID
     * @return 最后一个添加的文本的草稿ID
     * @throws Exception IO异常
     */
    public String addTextFromSrtFile(String filePath, String draftId) throws Exception {
        log.info("正在添加SRT字幕到草稿...");
        try {
            // 指定UTF-8编码读取文件
            String content = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
            // 清理数据
            // content = content.trim().replaceAll("[^\\x20-\\x7e\\x{4e00}-\\x{9fff}]", "");
            return addTextFromSrt(content, draftId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 简化版本：添加SRT字幕视频到草稿
     *
     * @param filePath SRT字幕文件
     * @param draftId  草稿ID
     * @return 最后一个添加的文本的草稿ID
     * @throws Exception IO异常
     */
    public String addVideoFromSrtFile(String filePath, String draftId, String topic) throws Exception {
        log.info("正在添加SRT字幕视频到草稿...");
        try {
            // 指定UTF-8编码读取文件
            String content = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
            // 清理数据
            // content = content.trim().replaceAll("[^\\x20-\\x7e\\x{4e00}-\\x{9fff}]", "");
            return addVideoFromSrt(content, draftId, topic);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 解析SRT字幕文件内容并将视频添加到草稿
     *
     * @param srtContent SRT字幕内容
     * @param draftId    草稿ID
     * @return 最后一个添加的文本的草稿ID
     * @throws Exception IO异常
     */
    public String addVideoFromSrt(String srtContent, String draftId, String topic) throws Exception {

        String[] lines = srtContent.split("\n");
        String lastDraftId = draftId;
        List<Map<String, Object>> srt = new ArrayList<>();
        double jrztStart = 0, topicEnd = 0, toalEnd = 0,jrztEnd = 0;
        for (int i = 0; i < lines.length; i++) {
            String line = lines[i].trim();

            // 检查是否为字幕序号行
            if (line.matches("\\d+") && i + 1 < lines.length) {
                // 下一行应该是时间码
                String timeLine = lines[i + 1].trim();
                if (timeLine.contains("-->")) {
                    String[] times = timeLine.split("-->");
                    if (times.length == 2 && i + 2 < lines.length) {
                        // 解析正在时间
                        double startTime = parseSrtTime(times[0].trim());
                        // 解析结束时间
                        double endTime = parseSrtTime(times[1].trim());

                        // 获取字幕文本（可能跨越多行）
                        StringBuilder textBuilder = new StringBuilder();
                        int j = i + 2;
                        while (j < lines.length && !lines[j].trim().isEmpty() && !lines[j].trim().matches("\\d+")) {
                            if (textBuilder.length() > 0) {
                                textBuilder.append("\n");
                            }
                            textBuilder.append(lines[j].trim());
                            j++;
                        }

                        String text = textBuilder.toString();
                        if (text.equalsIgnoreCase("今日主题")) {
                            jrztStart = startTime;
                            jrztEnd = endTime;

                        }
                        if (text.equalsIgnoreCase(topic)) {
                            topicEnd = endTime;
                        }
                        if (i == lines.length -1 ) {
                            toalEnd = endTime;
                        }
                        i = j - 1; // 更新索引位置
                    }
                }
            }
        }
        addEffect("荧幕噪点_II", draftId, 0.0, jrztStart, "effect_01");
        addEffect("荧幕噪点_II", draftId, topicEnd, toalEnd -3, "effect_02");
        addEffect("闭幕", draftId, toalEnd -3, toalEnd, "effect_03");
        // 添加音频
        draftId = addAudio(RES_SC_URL + "/dfd_cat_1757164709_197b3eee.MP3", jrztEnd, jrztEnd + 1.9, draftId,
                10.6, jrztEnd, null,null,null,null, null, 1920, 1080);
        // 生成分镜数据
        JSONArray fenjin = LyricFenjingUtil.generateFenjing(srtContent);
        // 处理分镜数据
        List<JSONObject> fenjins = LyricFenjingUtil.processFenjins(fenjin);
        double preStart = 0.0, preEnd = 0.0;
        List<String> usedVideoUrls = new ArrayList<>();
        for (JSONObject fj : fenjins) {
            // 解析正在时间
            double startTime = parseSrtTime(fj.getString("start"));
            // 解析结束时间
            double endTime = parseSrtTime(fj.getString("end"));
            double duration = endTime - preStart;
            preEnd = endTime;
            String videoUrl = getVideoUrl(fj.getString("keywords"), usedVideoUrls);
            if (usedVideoUrls.contains(videoUrl)) {
                for (int attempt = 0; attempt < 3; attempt++) {
                    videoUrl = getVideoUrl(fj.getString("keywords"), usedVideoUrls);
                    // 如果URL未使用过，则返回该URL
                    if (!usedVideoUrls.contains(videoUrl)) {
                        usedVideoUrls.add(videoUrl); // 标记为已使用
                        return videoUrl;
                    }
                    log.warn("第{}次尝试获取视频URL，但URL已使用: {}", attempt + 1, videoUrl);
                }
            } else {
                usedVideoUrls.add(videoUrl);
            }


            log.info("添加分镜视频素材...,开始：{}，结束：{}, {}", startTime, endTime, videoUrl);
            try {
                addVideo(videoUrl, 0.0, duration,
                        1920, 1080, draftId, null, null,
                        null, null, null, preStart, "video_main", null, duration, "模糊",
                        1.3, -1.0, null,
                        null, null, null, null, null, false, null,
                        null, null, 1.0, null, null, null);
                preStart = endTime;
            } catch (Exception e) {
                throw new Exception(e);
            }
        }
        ;

        // 开头 结尾视频
        String startVideoURL = RES_TPL_URL + "/60c7a1d34f090b36f17a73053094f2cc.mp4";
        addVideo(startVideoURL, 0.0, 8.2,
                1920, 1080, draftId, null, null,
                null, null, null, 0.0, "test_99", null, 8.2, null,
                null, -1.0, null,
                null, null, null, null, null, false, null,
                null, null, 1.0, null, null, null);
        String endVideoURL = RES_TPL_URL + "/60c7a1d34f090b36f17a73053094f2cc.mp4";
        addVideo(endVideoURL, parseFrameTime("00:03:36:28"), parseFrameTime("01:51:08"),
                1920, 1080, draftId, null, null,
                null, null, null, preEnd - 4.0, "test_99", null, 15.0, null,
                null, -1.0, null,
                null, null, null, null, null, false, null,
                null, null, 1.0, null, null, null);
        return lastDraftId;
    }


    /**
     * 解析帧格式时间码为秒数
     *
     * @param timeStr   帧格式时间字符串，格式为 HH:mm:ss:ff，例如 00:00:03:17
     * @param frameRate 帧率，默认为 30
     * @return 时间（秒）
     */
    private double parseFrameTime(String timeStr, int frameRate) {
        String[] parts = timeStr.split(":");
        if (parts.length == 4) {
            try {
                int hours = Integer.parseInt(parts[0]);
                int minutes = Integer.parseInt(parts[1]);
                int seconds = Integer.parseInt(parts[2]);
                int frames = Integer.parseInt(parts[3]);

                // 将帧数转换为秒的小数部分
                double frameSeconds = (double) frames / frameRate;

                return hours * 3600 + minutes * 60 + seconds + frameSeconds;
            } catch (NumberFormatException e) {
                log.warn("无法解析时间格式: {}", timeStr);
            }
        }
        return 0.0;
    }

    // 计算coverX和coverY并保留四位小数
    public double calculateCoverX(int valueX) {
        BigDecimal bd = BigDecimal.valueOf(valueX).divide(BigDecimal.valueOf(1920), 4, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }

    public double calculateCoverY(int valueY) {
        BigDecimal bd = BigDecimal.valueOf(valueY).divide(BigDecimal.valueOf(1080), 4, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }


    /**
     * 解析帧格式时间码为秒数（默认30帧/秒）
     *
     * @param timeStr 帧格式时间字符串，格式为 HH:mm:ss:ff，例如 00:00:03:17
     * @return 时间（秒）
     */
    public double parseFrameTime(String timeStr) {
        return parseFrameTime(timeStr, 30); // 默认30帧/秒
    }

    /**
     * 添加视频到草稿（完整版本）
     *
     * @param videoUrl           视频URL（必填，用于获取视频素材）
     * @param start              视频素材的起始截取时间（秒，选填，默认0）
     * @param end                视频素材的结束截取时间（秒，选填，默认0，0通常表示截取至视频末尾）
     * @param width              画布宽度（选填，默认1920）
     * @param height             画布高度（选填，默认1080）
     * @param draftId            草稿ID（选填，用于关联目标草稿）
     * @param transformY         Y轴位置偏移（选填，默认0）
     * @param transformX         X轴位置偏移（选填，默认0）
     * @param scaleX             X轴缩放比例（选填，默认1）
     * @param scaleY             Y轴缩放比例（选填，默认1）
     * @param speed              视频播放速度（选填，默认1.0，大于1为加速，小于1为减速）
     * @param targetStart        视频在时间线上的起始位置（秒，选填，默认0）
     * @param trackName          轨道名称（选填，默认"video_main"）
     * @param relativeIndex      相对索引（选填，默认0，用于控制轨道内素材的排列顺序）
     * @param duration           视频素材的总时长（秒，选填，主动设置可以提升当前节点运行速度）
     * @param transition         转场类型（选填，如"云朵"等，需与支持的类型匹配）
     * @param transitionDuration 转场持续时间（秒，选填，默认0.5）
     * @param volume             视频音量（选填，默认1.0，范围通常为0.0-1.0）
     * @param maskType           蒙版类型（选填，如圆形、矩形等）
     * @param maskCenterX        蒙版中心X坐标（选填，默认0.5，相对屏幕宽度比例）
     * @param maskCenterY        蒙版中心Y坐标（选填，默认0.5，相对屏幕高度比例）
     * @param maskSize           蒙版大小（选填，默认1.0，相对屏幕高度比例）
     * @param maskRotation       蒙版旋转角度（选填，默认0.0度）
     * @param maskFeather        蒙版羽化程度（选填，默认0.0，值越大边缘越柔和）
     * @param maskInvert         是否反转蒙版（选填，默认false）
     * @param maskRectWidth      矩形蒙版宽度（选填，仅mask_type为矩形时有效）
     * @param maskRoundCorner    矩形蒙版圆角（选填，仅mask_type为矩形时有效）
     * @param backgroundBlur     背景模糊，1,2,3,4四档可选
     * @param alpha              透明度，0-1
     * @param composite_mode     合成模式，如 source-over, multiply, screen 等
     * @param flipHorizontal     镜像反转，默认false
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String addVideo(String videoUrl, Double start, Double end, Integer width, Integer height,
                           String draftId, Double transformY, Double transformX,
                           Double scaleX, Double scaleY, Double speed, Double targetStart,
                           String trackName, Integer relativeIndex, Double duration,
                           String transition, Double transitionDuration, Double volume,
                           String maskType, Double maskCenterX, Double maskCenterY,
                           Double maskSize, Double maskRotation, Integer maskFeather,
                           boolean maskInvert, Integer maskRectWidth, Integer maskRoundCorner,
                           Integer backgroundBlur, Double alpha, String composite_mode, Boolean flipHorizontal,
                           Double rotation) throws Exception {
        log.info("正在添加视频素材...");
        String url = API_URL + "/add_video";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("video_url", videoUrl);
        body.put("start", start);

        if (end != null) {
            body.put("end", end);
        }

        body.put("width", width);
        body.put("height", height);

        if (draftId != null) {
            body.put("draft_id", draftId);
        }

        body.put("transform_y", transformY);
        body.put("transform_x", transformX);
        body.put("scale_x", scaleX);
        body.put("scale_y", scaleY);

        if (speed != null) {
            body.put("speed", speed);
        }

        body.put("target_start", targetStart);

        if (trackName != null) {
            body.put("track_name", trackName);
        }

        body.put("relative_index", relativeIndex);

        if (duration != null) {
            body.put("duration", duration);
        }

        if (transition != null) {
            body.put("transition", transition);
        }

        body.put("transition_duration", transitionDuration);

        if (volume != null) {
            body.put("volume", volume);
        }

        if (maskType != null) {
            body.put("mask_type", maskType);
        }

        if (rotation != null) {
            body.put("rotation", rotation);
        }

        body.put("mask_center_x", maskCenterX);
        body.put("mask_center_y", maskCenterY);
        body.put("mask_size", maskSize);
        body.put("mask_rotation", maskRotation);
        body.put("mask_feather", maskFeather);
        body.put("mask_invert", maskInvert);

        if (maskRectWidth != null) {
            body.put("mask_rect_width", maskRectWidth);
        }

        if (maskRoundCorner != null) {
            body.put("mask_round_corner", maskRoundCorner);
        }

        // 新增参数
        if (backgroundBlur != null) {
            body.put("background_blur", backgroundBlur);
        }

        if (alpha != null) {
            body.put("alpha", alpha);
        }

        // 新增 composite_mode 参数
        if (composite_mode != null) {
            body.put("composite_mode", composite_mode);
        }

        if (flipHorizontal != null) {
            body.put("flip_horizontal", flipHorizontal);
        }

        // 发送POST请求，使用不安全的SSL连接
        String response = okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("添加视频失败：" + error);
        }
        return jsonObject.getJSONObject("output").getString("draft_id");
    }


    /**
     * 添加视频到草稿（简化版本）
     *
     * @param videoUrl 视频URL
     * @param draftId  草稿ID
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String addVideo2(String videoUrl, String draftId, double start, double end, double scaleX, double scaleY, double transformX, double transformY,
                            double speed, String trackName) throws Exception {
        log.info("正在添加视频到草稿...");
        String response = addVideo(videoUrl, start, end, 1920, 1080, draftId, transformY, transformX, scaleX, scaleY,
                speed, null, trackName, 0, null, null, null, null,
                null, null, null, null, null, null, false,
                null, null, null, null, null, null, null);

        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("添加视频失败：" + error);
        }
        return jsonObject.getJSONObject("output").getString("draft_id");
    }

    /**
     * 获取文本介绍类型
     *
     * @return 响应内容
     * @throws Exception IO异常
     */
    public String getTextIntroTypes() throws Exception {
        String url = API_URL + "/get_text_intro_types";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "text/plain");

        // 发送GET请求，使用不安全的SSL连接
        return okHttpUtils.get(url, headers, true);
    }

    /**
     * 获取视频场景特效类型列表
     *
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String getVideoSceneEffectTypes() throws Exception {
        String url = API_URL + "/get_video_scene_effect_types";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "text/plain");

        // 发送GET请求，使用不安全的SSL连接
        return okHttpUtils.get(url, headers, true);
    }


    /**
     * 添加特效到草稿（完整版本）
     *
     * @param effectType 特效类型名称（必填，需从系统支持的特效列表中选择，如:MV封面）
     * @param start      特效开始时间（秒，选填，默认0）
     * @param end        特效结束时间（秒，选填，默认3.0）
     * @param draftId    草稿ID（选填，指定要添加特效的目标草稿，若未传或对应草稿不存在，可能自动创建新草稿）
     * @param trackName  特效轨道名称（选填，默认"effect_01"，用于区分不同特效轨道）
     * @param params     特效参数列表（选填，未提供的参数将使用默认值，具体参数取决于特效类型）
     * @param width      画布宽度（选填，默认1080）
     * @param height     画布高度（选填，默认1920）
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String addEffect(String effectType, String effectCategory, Double start, Double end, String draftId,
                            String trackName, List<Object> params, Integer width, Integer height) throws Exception {
        String url = API_URL + "/add_effect";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("effect_type", effectType);
        if (effectCategory != null) {
            body.put("effect_category", effectCategory);
        } else {
            body.put("effect_category", "scene");
        }
        if (start != null) {
            body.put("start", start);
        }

        if (end != null) {
            body.put("end", end);
        }

        if (draftId != null) {
            body.put("draft_id", draftId);
        }

        if (trackName != null) {
            body.put("track_name", trackName);
        }

        if (params != null) {
            body.put("params", params);
        }

        if (width != null) {
            body.put("width", width);
        }

        if (height != null) {
            body.put("height", height);
        }

        // 发送POST请求，使用不安全的SSL连接
        return okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
    }

    /**
     * 添加特效到草稿（简化版本）
     *
     * @param effectType 特效类型名称（必填）
     * @param draftId    草稿ID（可选）
     * @return draft_id
     * @throws Exception IO异常
     */
    public String addEffect(String effectType, String draftId, Double start, Double end, String trackName) throws Exception {
        String response = addEffect(effectType, null, start, end, draftId, trackName, null, 1920, 1080);
        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("添加特效失败：" + error);
        }
        return jsonObject.getJSONObject("output").getString("draft_id");
    }

    /**
     * 搜索贴纸
     *
     * @param keywords 搜索关键词（必填，用于在贴纸库中查找相关贴纸）
     * @return 响应结果
     * @throws Exception IO异常
     */
    public String searchSticker(String keywords) throws Exception {
        String url = API_URL + "/search_sticker";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("keywords", keywords);

        // 发送POST请求，使用不安全的SSL连接
        return okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
    }

    /**
     * 搜索贴纸
     *
     * @param draftId 草稿id（必填）
     * @return 响应结果
     * @throws Exception IO异常
     */
    public JSONObject queryDraftStatus(String draftId) throws Exception {
        String url = API_URL + "/query_draft_status";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("task_id", draftId);

        // 发送POST请求，使用不安全的SSL连接
        String response = okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("获取草稿状态失败：" + error);
        }
        return jsonObject.getJSONObject("output");
    }

    /**
     * 查询音频长度
     *
     * @param audioUrl 必填）
     * @return 响应结果
     * @throws Exception IO异常
     */
    public double getudioAuration(String audioUrl) throws Exception {
        String url = API_URL + "/get_audio_duration";

        // 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + API_KEY);
        headers.put("Content-Type", "application/json");

        // 构建请求体
        Map<String, Object> body = new HashMap<>();
        body.put("audio_url", audioUrl);

        // 发送POST请求，使用不安全的SSL连接
        String response = okHttpUtils.postJson(url, JSON.toJSONString(body), headers, true);
        JSONObject jsonObject = JSON.parseObject(response);
        String error = jsonObject.getString("error");
        if (StringUtils.isNotBlank(error)) {
            throw new Exception("获取音频长度失败：" + error);
        }
        return jsonObject.getDouble("output");
    }


    public void genMusicCraft(String songName, String songAuthor, String audioUrl, String srtPath, double audioDurations) {
        // 创建JyUtils对象

        //String songName = "月亮照山川";
        //String songAuthor = "窝窝";
        //String audioUrl = jyUtils.RES_SC_URL +  "/0904/1.mp3";
        //String srtPath = "E:\\自媒体\\素材\\sc\\0904\\1.srt";
        double audioDuration = audioDurations;// parseFrameTime(audioDurations);
        //        String result = jyUtils.searchSticker("音乐");
        //        log.info("result: {}",result);
        // 创建草稿
        try {
            // 创建草稿
            String draftId = createDraftAndGetId();
            System.out.println(draftId);
            // 添加音频
            draftId = addAudio2(audioUrl, draftId, null, null, null);
            System.out.println(draftId);
            // 添加图片到草稿
            //String imageUrl = "https://coze-1306981891.cos.ap-chengdu.myqcloud.com/%E5%9B%BE%E7%89%87%E9%A3%8E%E6%A0%BC%E8%B0%83%E6%95%B4%20%283%29.png";
            //draftId = addImage(imageUrl, draftId);
            // System.out.println(draftId);
            // 添加字幕文件（因为字幕有时间坐标）
            draftId = addTextFromSrtFile(srtPath, draftId);
            System.out.println(draftId);
            // 固定字幕 -2135040
            List<Map<String, Object>> textStyles = new ArrayList<>();
            Map<String, Object> ts = new HashMap<>();
            ts.put("end", 18);
            Map<String, Object> style = new HashMap<>();
            style.put("bold", true);
            ts.put("style", style);
            textStyles.add(ts);
            draftId = addText("A song and a story", parseFrameTime("00:00:03:17"), parseFrameTime("00:00:20:00"),
                    draftId, calculateCoverY(-725), calculateCoverX(-1112),
                    "默陌手写", "#FFFFFF", 15.0, "test_11", null, null, null, null, null, null, null,
                    null, null, null,
                    "打字机_II", 0.5, "渐隐", 0.5,
                    1920, 1080, textStyles, null, null,
                    null, null, null,
                    true, 0.00, -45.00, "#00000",
                    8, 0.33, 0.3, 0.3);
            ts.put("end", "一首歌一个故事".length());
            style.put("bold", false);
            ts.put("style", style);
            draftId = addText("一首歌一个故事", parseFrameTime("00:00:03:17"), parseFrameTime("00:00:20:00"),
                    draftId, calculateCoverY(-620), calculateCoverX(-1092),
                    "圆体", "#FFFFFF", 15.0, "test_22", null, null, null, null, null, null, null,
                    null, null, null,
                    "打字机_II", 0.5, "渐隐", 0.5,
                    1920, 1080, textStyles, null, null,
                    null, null, null,
                    true, 0.00, -45.00, "#00000",
                    8, 0.33, 0.2, 0.2);
            draftId = addText(songName, parseFrameTime("00:00:01:18"), parseFrameTime("00:00:08:29"),
                    draftId, calculateCoverY(562), calculateCoverX(-687),
                    "圆体", "#FFFFFF", 15.0, "test_33", null, null, null, null, null, null, null,
                    null, null, null,
                    "开幕", 1.6, "扭曲模糊", 1.2, 1920, 1080, null,
                    null, null, null, null, null, true, 0.00, -45.00, "#00000",
                    8, 0.33, 0.6, 0.6);
            draftId = addText("演唱：" + songAuthor, parseFrameTime("00:00:01:18"), parseFrameTime("00:00:08:29"),
                    draftId, calculateCoverY(366), calculateCoverX(-342),
                    "圆体", "#FFFFFF", 15.0, "test_44", null, null, null, null, null, null, null,
                    null, null, null, "开幕", 1.6, "扭曲模糊", 1.2, 1920, 1080, null,
                    null, null, null, null, null, true, 0.00, -45.00, "#00000",
                    8, 0.33, 0.36, 0.36);
            // 开头 云烟效果视频
            String start1VideoUrl = RES_TPL_URL + "/FW-6EBW--MLV0-389L-BWRL-KVFBKHRQJBBZ.mp4";
            double startTime1 = parseFrameTime("00:00:00:06");
            double vstartDuration1 = parseFrameTime("00:00:01:18") - startTime1;
            draftId = addVideo(start1VideoUrl, 0.0, 0.0,
                    1920, 1080, draftId, calculateCoverY(665), calculateCoverX(-219),
                    1.59, 1.59, 3.6 / vstartDuration1, startTime1, "test_55", null, vstartDuration1, "模糊",
                    0.7, 0.0, null,
                    null, null, null, null, null, false, null,
                    null, null, 1.0, "screen", null, null);
            String start2VideoUrl = RES_TPL_URL + "/W2-KAWE--GNLO-4S73-L5VZ-QPC4S1OT3MD1.mp4";
            double startTime2 = parseFrameTime("00:00:01:19");
            double vstartDuration2 = parseFrameTime("00:00:03:17") - startTime2;
            draftId = addVideo(start2VideoUrl, 0.0, 0.0,
                    1920, 1080, draftId, calculateCoverY(665), calculateCoverX(-219),
                    1.59, 1.59, 3.9 / vstartDuration2, startTime2, "test_55", null, vstartDuration2, null,
                    null, 0.0, null,
                    null, null, null, null, null, false, null,
                    null, null, 1.0, "screen", null, null);

            addEffect("光线扫描", draftId, 0.0, parseFrameTime("00:00:05:20"), "effect_01");

            // 背景视频 相当于滤色
            String bgVideoUrl = RES_TPL_URL + "/L4-XRO7--O4KS-ACX0-UR4U-JRODDCKFAIP7.mp4";
            double vlong = parseFrameTime("00:00:29:00");
            long num = (long) Math.ceil(audioDuration / vlong);
            double lastSegmentDuration = audioDuration % vlong;
            for (int i = 0; i < num; i++) {
                if (i == num - 1 && lastSegmentDuration > 0) {
                    // 处理最后一个片段，它的时长是 lastSegmentDuration
                    draftId = addVideo(bgVideoUrl, 0.0, lastSegmentDuration,
                            1920, 1080, draftId, 0.0, 0.0,
                            1.77, 1.77, 11.6 / lastSegmentDuration, vlong * i, "test_66", null, lastSegmentDuration, null,
                            null, 0.0, null,
                            null, null, null, null, null, false, null,
                            null, null, 0.1, null, null, 90.0);
                } else {
                    // 处理完整片段
                    draftId = addVideo(bgVideoUrl, 0.0, vlong,
                            1920, 1080, draftId, 0.0, 0.0,
                            1.77, 1.77, 11.6 / vlong, vlong * i, "test_66" + i, null, vlong, "模糊",
                            null, 0.0, null,
                            null, null, null, null, null, false, null,
                            null, null, 0.1, null, null, 90.0);
                }
            }

            String finalDraftId = draftId;

            // 异步执行延迟5秒的任务
            CompletableFuture.runAsync(() -> {
                try {
                    // 延迟5秒
                    Thread.sleep(5000);
                    // 在这里执行你需要延迟执行的任务
                    log.info("3秒延迟任务执行完成");
                    // 例如：执行其他业务逻辑
                    int progress = 0;
                    do {
                        JSONObject status = null;
                        try {
                            status = queryDraftStatus(finalDraftId);
                            progress = status.getIntValue("progress");
                            log.info("进度：{}%，{}/{}", status.getString("progress"), status.getIntValue("completed_files"), status.getIntValue("total_files"));
                            Thread.sleep(1000);
                        } catch (Exception e) {
                            log.error("查询进度失败:{}", e.getMessage());
                        }
                    } while (progress != 100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.error("延迟任务被中断", e);
                } catch (Exception e) {
                    log.error("延迟任务执行出错", e);
                }
            });
            try {
                String result = saveDraft(finalDraftId, songName, null);
                log.info("草稿保存成功，URL: {}", result);
            } catch (Exception e) {
                log.error("保存草稿失败:{}", e.getMessage());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void genTopic() {
        try {

            // 创建草稿
            String draftId = createDraftAndGetId();
            System.out.println(draftId);
            //
            String srtPath = "E:\\自媒体\\素材\\sc\\0906\\1.srt";
//            System.out.println(draftId);
            // 添加字幕文件（因为字幕有时间坐标）
            draftId = addVideoFromSrtFile(srtPath, draftId, "回忆");
//            System.out.println(draftId);
            draftId = addText("测试", 0, 2, draftId, null, null, null, null, null, null, null, null,
                    null, null, null, null, null, null, null, null,
                    null, null, null, null, 1920,
                    1080, null, null, null, null, null, null, null, null,
                    null, null, null, null, null, null);
            String finalDraftId = draftId;
//
//            // 异步执行延迟5秒的任务
//            CompletableFuture.runAsync(() -> {
//                try {
//                    // 延迟5秒
//                    Thread.sleep(5000);
//                    // 在这里执行你需要延迟执行的任务
//                    log.info("3秒延迟任务执行完成");
//                    // 例如：执行其他业务逻辑
//                    int progress = 0;
//                    do {
//                        JSONObject status = null;
//                        try {
//                            status = queryDraftStatus(finalDraftId);
//                            progress = status.getIntValue("progress");
//                            log.info("进度：{}%，{}/{}", status.getString("progress"), status.getIntValue("completed_files"), status.getIntValue("total_files"));
//                            Thread.sleep(1000);
//                        } catch (Exception e) {
//                            log.error("查询进度失败:{}", e.getMessage());
//                        }
//                    } while (progress != 100);
//                } catch (InterruptedException e) {
//                    Thread.currentThread().interrupt();
//                    log.error("延迟任务被中断", e);
//                } catch (Exception e) {
//                    log.error("延迟任务执行出错", e);
//                }
//            });
            try {
                String result = saveDraft(finalDraftId, null, null);
                log.info("草稿保存成功，URL: {}", result);
            } catch (Exception e) {
                log.error("保存草稿失败:{}", e.getMessage());
            }
        } catch (Exception e) {
            log.error("延迟任务执行出错", e);
        }
    }

    public static void main(String[] args) throws Exception {
        JyUtils jyUtils = new JyUtils();
//        jyUtils.setRES_TPL_URL("/tpl/music");
//        jyUtils.setAPI_URL("http://127.0.0.1:9001");
//        jyUtils.setRES_SC_URL("/sc");
//        jyUtils.setVIDEO_PATH("E:\\自媒体\\素材\\视频\\横屏");
//        jyUtils.setJY_CRAFT_PATH("D:\\my\\自媒体\\JianyingPro Drafts");
//        jyUtils.setRES_VIDEO_URL("/视频/横屏");
        String audioUrl = jyUtils.RES_SC_URL + "/0904/1.mp3";
        String srtPath = "E:\\自媒体\\素材\\sc\\0904\\1.srt";
        // String audioDuration = "00:02:48:15";
        //jyUtils.genMusicCraft("漂泊2222", "张艺迈", audioUrl, srtPath, jyUtils.getudioAuration(audioUrl));
        jyUtils.genTopic();
    }
}
